#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>

typedef struct {
    int bottom;
    int top;
    int elems[10];
}buff;


sem_t full, empty;
pthread_mutex_t mutex;

void * preducer(void * arg){
    buff * b = (buff *) arg;
    int count = 0;
    while(1){
        sleep(rand() % 3);
        sem_wait(&empty);
        pthread_mutex_lock(&mutex);

        b->elems[b->top] = rand() % 100;
        b->top++;

        for(int i = 0; i < b->top; i++){
            printf("%d  ", b->elems[i]);
        }
        printf("\tpreduce : %d", b->elems[b->top-1]);
        printf("\n");

        pthread_mutex_unlock(&mutex);
        sem_post(&full);
        count ++;
        if(count > 30) break;
    }

    return 0;
}

void * consumer(void *arg){
    buff * b = (buff *)arg;
    int count = 0;
    while(1){
        sleep(rand() % 3);
        sem_wait(&full);
        pthread_mutex_lock(&mutex);

        b->top--;
        for(int i = 0; i < b->top; i++){
            printf("%d  ", b->elems[i]);
        }
        printf("\tcomsume : %d", b->elems[b->top]);
        printf("\n");

        pthread_mutex_unlock(&mutex);
        sem_post(&empty);

        count ++;
        if(count >30) break;
    }

    return 0;
}

int main(){
    pthread_mutex_init(&mutex, NULL);
    sem_init(&empty, 0, 10);
    sem_init(&full, 0, 0);

    buff b = {0, 0, {0}};

    pthread_t tid_1;
    pthread_t tid_2;
    pthread_attr_t attr;
    pthread_attr_init(&attr);
    pthread_create(&tid_1, &attr, preducer, (void *)&b);
    pthread_create(&tid_2, &attr, consumer, (void *)&b);

    void * r1, * r2;
    pthread_join(tid_1, &r1);
    pthread_join(tid_2, &r2);

    return 0;
}